package cn.lingyangwl.agile.gateway.filter;

import cn.lingyangwl.agile.gateway.config.MyGatewayProperties;
import cn.lingyangwl.agile.model.constants.RequestCons;
import cn.lingyangwl.agile.model.constants.SecurityCons;
import cn.lingyangwl.framework.log.common.LogCons;
import cn.lingyangwl.framework.log.utils.MDCTraceUtils;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 全局拦截器
 * 1. 对请求头中参数进行处理 from 参数进行清洗 2. 重写StripPrefix = 1,支持全局
 * 2. 支持swagger添加X-Forwarded-Prefix header （F SR2 已经支持，不需要自己维护）
 * @author shenguangyang
 */
@Slf4j
@Component
public class LyRequestGlobalFilter implements GlobalFilter, Ordered {
	@Resource
	private MyGatewayProperties properties;

	/**
	 * Process the Web request and (optionally) delegate to the next {@code WebFilter}
	 * through the given {@link GatewayFilterChain}.
	 * @param exchange the current server exchange
	 * @param chain provides a way to delegate to the next filter
	 * @return {@code Mono<Void>} to indicate when request processing is complete
	 */
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		String path = exchange.getRequest().getPath().toString();
		String loginId =  exchange.getRequest().getHeaders().getFirst(LogCons.LOGIN_ID);
		// 排除websocket
		if ((StringUtils.isNotEmpty(loginId) && loginId.length() >= 16) && !path.contains("ws")) {
			throw new BizException("请求头中loginId值必须<=16");
		}

		ServerHttpRequest request = exchange.getRequest().mutate().headers(httpHeaders -> {
			// 清洗请求头中from 参数
			httpHeaders.remove(SecurityCons.FROM_SOURCE);

			// 设置请求时间
			httpHeaders.put(RequestCons.Headers.REQUEST_START_TIME,
					Collections.singletonList(String.valueOf(System.currentTimeMillis())));

			// 设置traceId
			httpHeaders.put(LogCons.TRACE_ID, Collections.singletonList(MDCTraceUtils.getTraceId()));

			// 设置登录id, 前端会获取登录返回的loginId, 如果没有登录就随机生成一个
			httpHeaders.put(LogCons.LOGIN_ID, Collections.singletonList(loginId));

			Set<String> addRequestHeaders = properties.getSign().stream()
					.flatMap(e -> e.getConfig().stream())
					.filter(e -> CollectionUtils.isNotEmpty(e.getAddRequestHeader()))
					.filter(e -> StringUtils.matches(path, new ArrayList<>(e.getIncludeUrls())))
					.flatMap(e -> e.getAddRequestHeader().stream()).collect(Collectors.toSet());
			for (String addRequestHeader : addRequestHeaders) {
				String[] split = addRequestHeader.split("=");
				String key = split[0];
				String value = split[1];
				httpHeaders.put(key, Collections.singletonList(value));
			}

		}).build();

		// 2. 重写StripPrefix
//		addOriginalRequestUrl(exchange, request.getURI());
//		String rawPath = request.getURI().getRawPath();
//		String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/")).skip(1L)
//				.collect(Collectors.joining("/"));
//
//		ServerHttpRequest newRequest = request.mutate().path(newPath).build();
//		exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());

		return chain.filter(exchange.mutate().request(request.mutate().build()).build());
	}

	@Override
	public int getOrder() {
		return HIGHEST_PRECEDENCE + 10;
	}

}
